package com.devyk.av.rtmp.library.widget

import android.content.Context
import android.graphics.SurfaceTexture
import android.util.AttributeSet
import android.view.Surface
import android.view.WindowManager
import com.devyk.av.rtmp.library.callback.ICameraOpenListener
import com.devyk.av.rtmp.library.camera.CameraHolder
import com.devyk.av.rtmp.library.camera.Watermark
import com.devyk.av.rtmp.library.camera.renderer.CameraRenderer
import com.devyk.av.rtmp.library.config.CameraConfiguration
import com.devyk.av.rtmp.library.config.RendererConfiguration
import com.devyk.av.rtmp.library.utils.LogHelper


/**
 * <pre>
 *     author  : devyk on 20-07-07 22:47
 *     blog    : https://juejin.im/user/578259398ac24700613a3fb/posts
 *     github  : https://github.com/yangkun19921001
 *     mailbox : yang1001yk@gmail.com
 *     desc    : This is CameraView
 * </pre>
 */
public open class CameraView : GLSurfaceView, SurfaceTexture.OnFrameAvailableListener {


    /**
     * Camera 渲染器
     */
    protected lateinit var renderer: CameraRenderer


    /**
     * 相机预览的纹理 ID
     */
    protected var mFBOBindTextureId = -1;
    protected var mCameraTexture = -1;

    protected var mCameraOpenListener: ICameraOpenListener? = null

    /**
     * 相机预览默认配置
     */
    private var mCameraConfiguration = CameraConfiguration.createDefault()


    /**
     * 默认后置摄像头
     */
    private var cameraId = CameraConfiguration.Facing.BACK


    constructor(context: Context?) : this(context, null)
    constructor(context: Context?, attrs: AttributeSet?) : this(context, attrs, 0)
    constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(
        context, attrs, defStyleAttr
    )


    public fun startPreview(cameraConfiguration: CameraConfiguration) {
        this.mCameraConfiguration = cameraConfiguration
        cameraId = cameraConfiguration.facing
        // 创建 CameraRender
        renderer = CameraRenderer(context!!)
        val configuration = RendererConfiguration.Builder()
            .setRenderer(renderer)
            .setRendererMode(RENDERER_MODE_CONTINUOUSLY)
            .build()
        super.configureRenderer(configuration)
        // 第一次需要初始化预览角度
        previewAngle(context)
        addRendererListener()
    }

    private fun addRendererListener() {
        renderer.setOnRendererListener(object : CameraRenderer.OnRendererListener {
            override fun onCreate(surfaceTexture: SurfaceTexture, textureID: Int) {
                // 这个纹理id由renderer创建，需要注意的是 surfaceTexture 中的纹理id和textureId不是同一个值
                mFBOBindTextureId = textureID
                CameraHolder.instance().setConfiguration(mCameraConfiguration)
                CameraHolder.instance().openCamera()
                // 设置纹理, 相机会将流输出到这个纹理上
                CameraHolder.instance().setSurfaceTexture(surfaceTexture, this@CameraView)
                CameraHolder.instance().startPreview()
                LogHelper.e(TAG, "FBOBindTextureId:${mFBOBindTextureId}")
                // 拿到创建的相机预览纹理和绑定FBO的纹理之后，通知采集线程开始工作
                mCameraOpenListener?.onCameraOpen()
            }

            override fun onCreate(cameraTextureId: Int, textureID: Int) = Unit

            override fun onDraw() {
                // 渲染线程准备好绘制了，触发从相机采集流中拉取最新的纹理信息。
                // 这里有个概念是: 相机是在另外一个线程中采集数据的，不论渲染线程是否拉取数据，都会采集到缓存区，
                // 渲染进程在需要的时候，通过该方法，从相机采集流(缓冲区)中，拉取最新的相机数据。
                // 然后，相机会将最新的数据，保存到 opengl 的片元程序的 samplerExternalOES 类型的数据中。
                CameraHolder.instance().updateTexImage()
            }
        })
    }

    /**
     * 释放 Camera 资源的时候调用
     */
    public open fun releaseCamera() {
        CameraHolder.instance().stopPreview()
        CameraHolder.instance().releaseCamera()
        CameraHolder.instance().release()
    }

    @Synchronized
    public open fun switchCamera(): Boolean {
        var ret = CameraHolder.instance().switchCamera()
        if (ret) {
            if (cameraId == CameraConfiguration.Facing.BACK) {
                cameraId = CameraConfiguration.Facing.FRONT
            } else {
                cameraId = CameraConfiguration.Facing.BACK
            }
            renderer.switchCamera(object : CameraRenderer.OnSwitchCameraListener {
                override fun onChange(): Boolean {
                    previewAngle(context)
                    return true
                }
            })
        }
        return ret
    }

    /**
     * 设置水印
     */
    public open fun setWatermark(watermark: Watermark) {
        renderer.setWatermark(watermark)
    }

    override fun onFrameAvailable(surfaceTexture: SurfaceTexture?) {
        LogHelper.e(TAG, "相机纹理刷新");
        // 相机显示空闲，可以设置新纹理
    }


    fun previewAngle(context: Context) {
        previewAngle(context, true)
    }

    fun previewAngle(context: Context, isResetMatrix: Boolean) {
        val rotation =
            (context.applicationContext.getSystemService(Context.WINDOW_SERVICE) as WindowManager).defaultDisplay.rotation
        LogHelper.d(TAG, "旋转角度：" + rotation)
        renderer.resetMatrix()
        when (rotation) {
            Surface.ROTATION_0 -> {
                if (cameraId == CameraConfiguration.Facing.BACK) {
                    renderer.setAngle(90, 0, 0, 1);
                    renderer.setAngle(180, 1, 0, 0);
                } else {
                    renderer.setAngle(90, 0, 0, 1);
                }
            }

            Surface.ROTATION_90 -> {
                if (cameraId == CameraConfiguration.Facing.BACK) {
                    renderer.setAngle(180, 0, 0, 1);
                    renderer.setAngle(180, 0, 1, 0);
                } else {
                    renderer.setAngle(180, 0, 0, 1);
                }
            }

            Surface.ROTATION_180 -> {
                if (cameraId == CameraConfiguration.Facing.BACK) {
                    renderer.setAngle(90, 0, 0, 1);
                    renderer.setAngle(180, 0, 1, 0);
                } else {
                    renderer.setAngle(-90, 0, 0, 1);
                }
            }

            Surface.ROTATION_270 -> {
                if (cameraId == CameraConfiguration.Facing.BACK) {
                    renderer.setAngle(180, 0, 1, 0);
                } else {
                    renderer.setAngle(0, 0, 0, 1);
                }
            }
        }
    }

    /**
     * 拿到纹理 ID
     */
    public fun getFBOBindTextureId(): Int = mFBOBindTextureId


    public fun addCameraOpenCallback(listener: ICameraOpenListener) {
        mCameraOpenListener = listener
    }

}